home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiniExamples / AppKit / TextORama / TurboTFCell.m < prev   
Text File  |  1995-06-12  |  7KB  |  253 lines

  1. /* TurboTFCell.m
  2.  *
  3.  *   TurboTFCell is a subclass of TextFieldCell which supports
  4.  *        a) length-watching on a string -- maxLength  [length of 0
  5.  *            indicates that length-watching is not active]
  6.  *        b) auto-jumping to nextText if the maximum is reached
  7.  *        c) acceptsReturn will cause the Return character to be
  8.  *            interpreted literally rather than as a signal to end editing
  9.  * 
  10.  *
  11.  * You may freely copy, distribute, and reuse the code in this example.
  12.  * NeXT disclaims any warranty of any kind, expressed or  implied, as to its
  13.  * fitness for any particular use.
  14.  *
  15.  * Written by:  Sharon Zakhour 
  16.  * Created:  Oct/91
  17.  */
  18.  
  19. #import "TurboTFCell.h"
  20.  
  21. @implementation TurboTFCell
  22.  
  23. /* In order for the length watching (and auto-jumping since that is 
  24.  * determined by length) to work properly, the character and text
  25.  * filters need to know the identity of the cell they are working with.
  26.  */
  27. static id theCell = NULL;
  28.  
  29. - init
  30. {
  31.     return [self initTextCell:""];
  32. }
  33.  
  34. - initTextCell: (const char*) aString
  35. {
  36.     [super initTextCell:aString];
  37.     
  38.     // Initialize these to the default TextField behavior
  39.     originalText = NULL;
  40.     customTextFilter = (NXTextFilterFunc)lengthFilter;
  41.     [self setAutoJump: NO forLength: 0];
  42.     [self setAcceptsReturn: NO];
  43.     return self;
  44. }
  45.  
  46. - free
  47. {
  48.     if (originalText)
  49.     free(originalText);
  50.     originalText = NULL;
  51.     return[super free];
  52. }
  53.  
  54. /* The primary reason I've overridden select: and edit: (below) is to set
  55.  * the local static variable "theCell" to self.  The filter functions must know
  56.  * about the current cell in order to query it for information on length,
  57.  * autojumping, etc.  The only way that a cell becomes active are
  58.  * through one of these methods.
  59.  */
  60. - select:(const NXRect *)aRect inView:controlView editor:textObj delegate:anObject start:(int)selStart length:(int)selLength
  61. {
  62.     /* do what the superclass would do */
  63.     [super select:aRect inView:controlView editor:textObj 
  64.         delegate:anObject start:selStart length:selLength];
  65.     
  66.     theCell = self;
  67.     if (maxLength && originalText)
  68.         strcpy(originalText, [self stringValue]);
  69.  
  70.     [textObj setTextFilter:(NXTextFilterFunc)customTextFilter];
  71.     [textObj setCharFilter:autoJumpCharFilter];
  72.     return self;
  73. }
  74.  
  75. /* The primary reason I've overridden edit: and select: (above) is to set
  76.  * the local static variable "theCell" to self.  The filter functions must know
  77.  * about the current cell in order to query it for information on length,
  78.  * autojumping, etc.  The only way that a cell becomes active are
  79.  * through one of these methods.
  80.  */
  81. - edit:(const NXRect *)aRect inView:controlView editor:textObj delegate:anObject event:(NXEvent *)theEvent
  82. {
  83.     /* do what the superclass would do */
  84.     [super edit:aRect inView:controlView editor:textObj 
  85.         delegate:anObject event:theEvent];
  86.  
  87.     theCell = self;
  88.     if (maxLength && originalText)
  89.         strcpy(originalText, [self stringValue]);
  90.  
  91.     [textObj setTextFilter:(NXTextFilterFunc)customTextFilter];
  92.     [textObj setCharFilter:autoJumpCharFilter];
  93.     return self;
  94. }
  95.  
  96. - setMaxLength: (int) length
  97. {
  98.     if (originalText)
  99.     {
  100.     free(originalText);
  101.     originalText = NULL;
  102.     }
  103.     maxLength = length;
  104.     if (length)
  105.     originalText = (char *)malloc(maxLength);
  106.     return self;
  107. }
  108.  
  109. - (int) maxLength;
  110. {
  111.     return maxLength;
  112. }
  113.  
  114. - setAutoJump: (BOOL) flag forLength: (int)length
  115. {
  116.     autoJump = flag;
  117.     [self setMaxLength: length];
  118.     return self;
  119. }
  120.  
  121. - (BOOL) autoJump
  122. {
  123.     return autoJump;
  124. }
  125.  
  126. - setAcceptsReturn: (BOOL) flag 
  127. {
  128.     acceptsReturn = flag;
  129.     return self;
  130. }
  131.  
  132. - (BOOL) acceptsReturn
  133. {
  134.     return acceptsReturn;
  135. }
  136.  
  137. - setOriginalText: (char *)aString
  138. {
  139.     if (originalText)
  140.     strcpy(originalText, aString);
  141.     return self;
  142. }
  143.  
  144. - (char *)originalText
  145. {
  146.     return originalText;
  147. }
  148.  
  149. - setCustomFilter: (NXTextFilterFunc) aFilter;
  150. {
  151.     customTextFilter = (NXTextFilterFunc)aFilter;
  152.     return self;
  153. }
  154.  
  155. - (NXTextFilterFunc) customTextFilter
  156. {
  157.     return (NXTextFilterFunc) customTextFilter;
  158. }
  159.  
  160.  
  161. /* Run the given string through the Cell's text filter to 
  162.  * see if it passes muster.
  163.  */
  164. - (BOOL) checkString: (char *)aString
  165. {
  166.     int     i, len;
  167.     char *cp;
  168.     id textObj;
  169.     void *fooPtr;
  170.     
  171.     if (customTextFilter == (NXTextFilterFunc)nil)
  172.         return YES;
  173.     
  174.     textObj = [[[self controlView] window] getFieldEditor :YES for: self];
  175.     for (i = 0, cp = aString; i < strlen(aString); i++, cp++)
  176.     {
  177.         len = 1;
  178.     // fooPtr will eliminate a compiler warning about "unused value"
  179.     fooPtr = (void*)(*(NXTextFilterFunc)customTextFilter)((id)textObj,
  180.         (unsigned char *)cp, (int *)&len, (int)i);
  181.     if (len == 0) 
  182.         return NO;
  183.     }
  184.     return YES;
  185. }
  186.  
  187. // This is the default text filter.  If another has been installed via the setCustomFilter:
  188. // method, then this one will not get called.
  189. char *lengthFilter(id textObj, char *inputText, int *inputLength, int position)
  190. {
  191.     int maxLength;
  192.     BOOL autoJump;
  193.    
  194.     maxLength = [theCell maxLength];
  195.     autoJump = [theCell autoJump];
  196.     
  197.     if (maxLength && !autoJump && [textObj textLength] > maxLength)
  198.     {
  199.     *inputLength = 0;
  200.     return "";
  201.     }
  202.     
  203.     return inputText;
  204. }
  205.  
  206. // This could easily be extended to include letters with diacritics.
  207. // See Chapter 6 Summary for KeyInfo for a full listing of keyboard
  208. // event information.
  209. #define IS_VALID_ASCII(ch)    ((ch) >= ' ' && (ch) <= '~')
  210.  
  211. unsigned short autoJumpCharFilter(unsigned short charCode, int flags, unsigned
  212. short charSet)
  213. {
  214.     NXSelPt     start, end;
  215.     NXEvent    *event, fakeEvent;
  216.     id            textObj;
  217.     int            curLength, maxLength;
  218.     BOOL         autoJump, acceptsReturn;
  219.     
  220.     maxLength = [theCell maxLength];
  221.     autoJump = [theCell autoJump];
  222.     acceptsReturn = [theCell acceptsReturn];
  223.     
  224.     event = [NXApp currentEvent];
  225.     textObj = [[[theCell controlView] window] getFieldEditor :YES for: theCell];
  226.     curLength = [textObj textLength] +1;
  227.     
  228.     /* Anything that's highlighted is going to get clobbered, so let's adjust */
  229.     [textObj getSel: &start : &end];
  230.     if (start.cp != end.cp)
  231.         curLength -= end.cp - start.cp; 
  232.  
  233.     // Currently acceptsReturn doesn't work very well with maxLength because
  234.     // it counts newlines which you probably don't want.  If you want something
  235.     // more sophisticated then you'll have to parse the runs!
  236.     if (acceptsReturn && charCode == NX_CR)
  237.     return NXEditorFilter(charCode, flags, charSet);
  238.     
  239.     // Watch out for interpreted rather than real keystrokes -- let them
  240.     // through even though we have reached our maximum length.
  241.     if (autoJump && maxLength && curLength > maxLength &&
  242.         IS_VALID_ASCII(charCode))
  243.     {
  244.     fakeEvent = *event;
  245.     fakeEvent.time++;
  246.     DPSPostEvent(&fakeEvent, YES);
  247.     return NX_TAB;
  248.     } 
  249.     return NXFieldFilter(charCode, flags, charSet);
  250. }
  251.  
  252. @end
  253.